package com.bnd.controller;

import com.bnd.common.BaseResponse;
import com.bnd.common.ResultUtils;
import com.bnd.config.SseEmitterUTF8;
import com.bnd.domain.CharacterInfo;
import com.bnd.service.CharacterInfoService;
import com.github.pagehelper.PageInfo;
import org.springframework.core.io.Resource;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.bnd.common.ErrorCode;
import org.springframework.web.bind.annotation.*;

import com.alibaba.dashscope.aigc.generation.Generation;
import com.alibaba.dashscope.aigc.generation.GenerationParam;
import com.alibaba.dashscope.aigc.generation.GenerationResult;
import com.alibaba.dashscope.common.Message;
import com.alibaba.dashscope.common.Role;
import com.bnd.config.AiConfig;
import com.bnd.service.ImageService;
import com.bnd.service.VoiceService;
import com.bnd.service.FileService;
import com.bnd.service.ContentSafetyService;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import java.util.*;


/**
 * 角色信息控制器
 */
@Slf4j
@RestController
@RequestMapping("/characterInfo")
@RequiredArgsConstructor
public class CharacterInfoController {

    private final CharacterInfoService characterInfoService;
    private final AiConfig aiConfig;
    private final ImageService imageService;
    private final VoiceService voiceService;
    private final FileService fileService;
    private final ContentSafetyService contentSafetyService;
    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    /**
     * 角色列表查询（分页）
     * @param keyword 搜索关键词
     * @param category 角色分类
     * @param pageNum 页码
     * @param pageSize 每页大小
     * @return 分页角色列表
     */
    @GetMapping("/list")
    public BaseResponse<PageInfo<CharacterInfo>> list(@RequestParam(value = "keyword", required = false) String keyword,
                                                      @RequestParam(value = "category", required = false, defaultValue = "全部") String category,
                                                      @RequestParam(value = "pageNum", required = false, defaultValue = "1") int pageNum,
                                                      @RequestParam(value = "pageSize", required = false, defaultValue = "8") int pageSize) {
        log.info("[角色列表接口] keyword={}, category={}, pageNum={}, pageSize={}", keyword, category, pageNum, pageSize);
        PageInfo<CharacterInfo> page = characterInfoService.pageSearch(keyword, category, pageNum, pageSize);
        return ResultUtils.success(page);
    }

    /**
     * 根据ID获取角色详情
     * @param id 角色ID
     * @return 角色详情信息
     */
    @GetMapping("/{id}")
    public BaseResponse<CharacterInfo> getCharacterInfoById(@PathVariable Long id) {
        try {
            CharacterInfo characterInfo = characterInfoService.getCharacterById(id);
            if (characterInfo != null) {
                return ResultUtils.success(characterInfo);
            } else {
                return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "角色信息不存在");
            }
        } catch (Exception e) {
            log.error("获取角色信息失败，角色ID: {}", id, e);
            return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "获取角色信息失败");
        }
    }

    /**
     * 创建角色（直接保存，不进行AI生成）
     * @param req 创建请求参数
     * @return 创建的角色信息
     */
    @PostMapping("/create")
    public BaseResponse<CharacterInfo> create(@RequestBody CreateReq req) {
        try {
            if (req == null || isBlank(req.getName()) || isBlank(req.getPrompt())) {
                return ResultUtils.error(ErrorCode.PARAMS_ERROR, "名称与提示词不能为空");
            }

            // 内容安全校验
            String nameBad = contentSafetyService == null ? null : contentSafetyService.checkText(req.getName());
            if (nameBad != null) {
                return ResultUtils.error(ErrorCode.PARAMS_ERROR, nameBad);
            }
            String promptBad = contentSafetyService == null ? null : contentSafetyService.checkText(req.getPrompt());
            if (promptBad != null) {
                return ResultUtils.error(ErrorCode.PARAMS_ERROR, promptBad);
            }

            // 直接使用用户已确定的信息，不再重新生成
            CharacterInfo ci = new CharacterInfo();
            ci.setName(req.getName().trim());
            ci.setPrompt(req.getPrompt().trim());
            ci.setIntro(isBlank(req.getIntro()) ? "" : req.getIntro().trim());
            ci.setImage(isBlank(req.getImage()) ? "" : req.getImage().trim());
            ci.setVoice(isBlank(req.getVoice()) ? aiConfig.getDashscope().getSsVoice() : req.getVoice().trim());
            ci.setVoiceUrl(isBlank(req.getVoiceUrl()) ? null : req.getVoiceUrl().trim());
            ci.setCategory(isBlank(req.getCategory()) ? "自定义" : req.getCategory().trim());
            ci.setTags(req.getTags() == null ? new ArrayList<>() : req.getTags());
            ci.setGreeting(isBlank(req.getGreeting()) ? "" : req.getGreeting().trim());
            ci.setIsFavorited(0);
            ci.setViewCount(0);
            ci.setIsDel(0);
            ci.setCreateTime(new Date());
            ci.setUpdateTime(new Date());

            boolean ok = characterInfoService.save(ci);
            if (!ok) { return ResultUtils.error(ErrorCode.OPERATION_ERROR, "保存角色失败"); }
            log.info("[创建角色] id={}, name={}", ci.getId(), ci.getName());
            // 清除角色列表缓存（新角色会影响列表）
            characterInfoService.clearCharacterListCache();
            ci.setCreateTime(null);
            ci.setUpdateTime(null);
            return ResultUtils.success(ci);
        } catch (Exception e) {
            log.error("[创建角色] 异常", e);
            return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "创建角色失败");
        }
    }



    /**
     * 获取可用音色列表
     * @return 音色ID列表
     */
    @GetMapping("/voices")
    public BaseResponse<List<String>> listVoices() {
        String def = aiConfig.getDashscope().getSsVoice();
        LinkedHashSet<String> voices = new LinkedHashSet<>();
        if (!isBlank(def)) voices.add(def);
        voices.addAll(Arrays.asList(
                "longqiang_v2",
                "longhan_v2",
                "longtian_v2",
                "longlaotie_v2",
                "libai_v2",
                "longjing_v2"
        ));
        return ResultUtils.success(new ArrayList<>(voices));
    }

    /**
     * 收藏角色
     * @param id 角色ID
     * @return 操作结果
     */
    @PostMapping("/favorite/{id}")
    public BaseResponse<String> favorite(@PathVariable Long id) {
        try {
            CharacterInfo info = characterInfoService.getById(id);
            if (info == null || info.getIsDel() != null && info.getIsDel() == 1) {
                return ResultUtils.error(ErrorCode.NOT_FOUND_ERROR, "角色不存在");
            }
            info.setIsFavorited(1);
            info.setUpdateTime(new Date());
            boolean ok = characterInfoService.updateById(info);
            if (!ok) { return ResultUtils.error(ErrorCode.OPERATION_ERROR, "收藏失败"); }
            // 清除相关缓存
            characterInfoService.clearCharacterDetailCache(id);
            characterInfoService.clearCharacterListCache();
            characterInfoService.clearCharacterFavoritesCache();
            return ResultUtils.success("收藏成功");
        } catch (Exception e) {
            log.error("收藏角色异常，id={}", id, e);
            return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "收藏角色异常");
        }
    }

    /**
     * 取消收藏角色
     * @param id 角色ID
     * @return 操作结果
     */
    @PostMapping("/unfavorite/{id}")
    public BaseResponse<String> unfavorite(@PathVariable Long id) {
        try {
            CharacterInfo info = characterInfoService.getById(id);
            if (info == null || info.getIsDel() != null && info.getIsDel() == 1) {
                return ResultUtils.error(ErrorCode.NOT_FOUND_ERROR, "角色不存在");
            }
            info.setIsFavorited(0);
            info.setUpdateTime(new Date());
            boolean ok = characterInfoService.updateById(info);
            if (!ok) { return ResultUtils.error(ErrorCode.OPERATION_ERROR, "取消收藏失败"); }
            // 清除相关缓存
            characterInfoService.clearCharacterDetailCache(id);
            characterInfoService.clearCharacterListCache();
            characterInfoService.clearCharacterFavoritesCache();
            return ResultUtils.success("已取消收藏");
        } catch (Exception e) {
            log.error("取消收藏角色异常，id={}", id, e);
            return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "取消收藏角色异常");
        }
    }

    /**
     * 获取收藏角色列表
     * @return 收藏的角色列表
     */
    @GetMapping("/favorites")
    public BaseResponse<List<FavoriteCharacterInfo>> getFavorites() {
        try {
            List<CharacterInfo> favorites = characterInfoService.listFavorites();
            List<FavoriteCharacterInfo> result = favorites.stream()
                    .map(this::convertToFavoriteInfo)
                    .collect(java.util.stream.Collectors.toList());
            return ResultUtils.success(result);
        } catch (Exception e) {
            log.error("获取收藏角色列表异常", e);
            return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "获取收藏角色列表失败");
        }
    }

    /**
     * 删除自定义角色（只能删除category为"自定义"的角色）
     * @param id 角色ID
     * @return 操作结果
     */
    @DeleteMapping("/delete/{id}")
    public BaseResponse<String> deleteCustom(@PathVariable Long id) {
        try {
            if (id == null || id <= 0) {
                return ResultUtils.error(ErrorCode.PARAMS_ERROR, "ID不合法");
            }
            CharacterInfo exist = characterInfoService.getById(id);
            if (exist == null || exist.getIsDel() != null && exist.getIsDel() == 1) {
                return ResultUtils.error(ErrorCode.NOT_FOUND_ERROR, "角色不存在");
            }
            if (!"自定义".equalsIgnoreCase(exist.getCategory())) {
                return ResultUtils.error(ErrorCode.NO_AUTH_ERROR, "仅允许删除自定义角色");
            }
            exist.setIsDel(1);
            exist.setUpdateTime(new Date());
            boolean ok = characterInfoService.updateById(exist);
            if (!ok) {
                return ResultUtils.error(ErrorCode.OPERATION_ERROR, "删除失败");
            }
            // 清除相关缓存
            characterInfoService.clearCharacterDetailCache(id);
            characterInfoService.clearCharacterListCache();
            return ResultUtils.success("删除成功");
        } catch (Exception e) {
            log.error("删除自定义角色异常，id={}", id, e);
            return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "删除角色异常");
        }
    }

    // ====== 辅助：单独生成简介/标签/头像（前端分步引导可用） ======

    /**
     * AI辅助生成角色简介
     * @param body 请求体，包含prompt字段
     * @return 生成的简介
     */
    @PostMapping("/assist/intro")
    public BaseResponse<String> assistIntro(@RequestBody Map<String, String> body) {
        String prompt = body == null ? null : body.get("prompt");
        if (isBlank(prompt)) { return ResultUtils.error(ErrorCode.PARAMS_ERROR, "prompt不能为空"); }
        String intro = generateIntro(prompt);
        if (isBlank(intro)) { return ResultUtils.error(ErrorCode.OPERATION_ERROR, "简介生成失败"); }
        return ResultUtils.success(intro);
    }

    /**
     * AI辅助生成角色标签
     * @param body 请求体，包含prompt字段
     * @return 生成的标签列表
     */
    @PostMapping("/assist/tags")
    public BaseResponse<List<String>> assistTags(@RequestBody Map<String, String> body) {
        String prompt = body == null ? null : body.get("prompt");
        if (isBlank(prompt)) { return ResultUtils.error(ErrorCode.PARAMS_ERROR, "prompt不能为空"); }
        List<String> tags = generateTags(prompt);
        if (tags == null || tags.isEmpty()) { return ResultUtils.error(ErrorCode.OPERATION_ERROR, "标签生成失败"); }
        return ResultUtils.success(tags);
    }

    /**
     * AI辅助生成角色头像
     * @param body 请求体，包含prompt字段
     * @return 生成的头像URL列表
     */
    @PostMapping("/assist/avatar")
    public BaseResponse<List<String>> assistAvatar(@RequestBody Map<String, Object> body) {
        try {
            String prompt = body == null ? null : (String) body.get("prompt");
            String size = body == null ? null : (String) body.getOrDefault("size", "1024*1024");
            Integer n = body == null ? 2 : (Integer) body.getOrDefault("n", 2);
            if (n == null || n < 1 || n > 4) { n = 2; }
            if (isBlank(prompt)) { return ResultUtils.error(ErrorCode.PARAMS_ERROR, "prompt不能为空"); }
            List<String> urls = imageService.textToImage(prompt, size, n);
            if (urls == null || urls.isEmpty()) { return ResultUtils.error(ErrorCode.OPERATION_ERROR, "头像生成失败"); }
            return ResultUtils.success(urls);
        } catch (Exception e) {
            log.error("头像生成异常", e);
            return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "头像生成异常");
        }
    }

    /**
     * 上传自定义头像
     * @param file 头像文件
     * @return 上传后的文件URL
     */
    @PostMapping("/avatar/upload")
    public BaseResponse<String> uploadAvatar(@RequestParam("file") org.springframework.web.multipart.MultipartFile file) {
        try {
            if (file == null || file.isEmpty()) {
                return ResultUtils.error(ErrorCode.PARAMS_ERROR, "图片文件不能为空");
            }
            String contentType = file.getContentType() == null ? "" : file.getContentType().toLowerCase();
            String filename = file.getOriginalFilename() == null ? "" : file.getOriginalFilename().toLowerCase();
            boolean typeOk = contentType.startsWith("image/")
                    || filename.endsWith(".jpg") || filename.endsWith(".jpeg")
                    || filename.endsWith(".png") || filename.endsWith(".webp");
            if (!typeOk) {
                return ResultUtils.error(ErrorCode.PARAMS_ERROR, "仅支持jpg/jpeg/png/webp图片");
            }
            // 大小限制：10MB
            long maxSize = 10L * 1024 * 1024;
            if (file.getSize() > maxSize) {
                return ResultUtils.error(ErrorCode.PARAMS_ERROR, "图片大小不能超过10MB");
            }

            String url = fileService.uploadFile(file);
            if (isBlank(url)) {
                return ResultUtils.error(ErrorCode.OPERATION_ERROR, "头像上传失败");
            }
            log.info("[头像上传] 成功，fileName={}, url={}", file.getOriginalFilename(), url);
            return ResultUtils.success(url);
        } catch (Exception e) {
            log.error("[头像上传] 处理失败", e);
            return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "头像上传失败: " + e.getMessage());
        }
    }

    /**
     * AI辅助生成角色招呼语
     * @param body 请求体，包含name和prompt字段
     * @return 生成的招呼语
     */
    @PostMapping("/assist/greeting")
    public BaseResponse<String> assistGreeting(@RequestBody Map<String, String> body) {
        String name = body == null ? null : body.get("name");
        String prompt = body == null ? null : body.get("prompt");
        if (isBlank(name) || isBlank(prompt)) {
            return ResultUtils.error(ErrorCode.PARAMS_ERROR, "角色名称和提示词不能为空");
        }
        String greeting = generateGreeting(name.trim(), prompt.trim());
        if (isBlank(greeting)) { return ResultUtils.error(ErrorCode.OPERATION_ERROR, "招呼语生成失败"); }
        return ResultUtils.success(greeting);
    }

    /**
     * 上传音频文件用于音色克隆
     * @param file 音频文件
     * @return 包含文件URL和音色ID的响应
     */
    @PostMapping("/voice/upload")
    public BaseResponse<Map<String, String>> uploadVoice(@RequestParam("file") org.springframework.web.multipart.MultipartFile file) {
        try {
            log.info("[音色上传] 开始处理音频文件: {}", file.getOriginalFilename());

            // 1. 上传音频文件
            String voiceUrl = fileService.uploadAudioFile(file);
            if (isBlank(voiceUrl)) {
                return ResultUtils.error(ErrorCode.OPERATION_ERROR, "音频文件上传失败");
            }

            // 2. 生成音色ID
            String voiceId = voiceService.generateVoice(voiceUrl);
            if (isBlank(voiceId)) {
                return ResultUtils.error(ErrorCode.OPERATION_ERROR, "音色生成失败");
            }

            Map<String, String> result = new HashMap<>();
            result.put("voiceUrl", voiceUrl);
            result.put("voiceId", voiceId);

            log.info("[音色上传] 成功生成音色, voiceUrl={}, voiceId={}", voiceUrl, voiceId);
            return ResultUtils.success(result);

        } catch (Exception e) {
            log.error("[音色上传] 处理失败", e);
            return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "音色上传失败: " + e.getMessage());
        }
    }

    /**
     * 根据音频URL生成音色
     * @param body 请求体，包含voiceUrl字段
     * @return 生成的音色ID
     */
    @PostMapping("/voice/generate")
    public BaseResponse<String> generateVoiceFromUrl(@RequestBody Map<String, String> body) {
        try {
            String voiceUrl = body == null ? null : body.get("voiceUrl");
            if (isBlank(voiceUrl)) {
                return ResultUtils.error(ErrorCode.PARAMS_ERROR, "音频文件URL不能为空");
            }

            log.info("[音色生成] 开始处理音频URL: {}", voiceUrl);

            String voiceId = voiceService.generateVoice(voiceUrl.trim());
            if (isBlank(voiceId)) {
                return ResultUtils.error(ErrorCode.OPERATION_ERROR, "音色生成失败");
            }

            log.info("[音色生成] 成功生成音色ID: {}", voiceId);
            return ResultUtils.success(voiceId);

        } catch (Exception e) {
            log.error("[音色生成] 处理失败", e);
            return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "音色生成失败: " + e.getMessage());
        }

    }

    /**
     * 角色音频播放（同步）
     * @param characterId 角色ID
     * @return 音频资源响应
     */
    @GetMapping("/voicePlay/{id}")
    public ResponseEntity<Resource> voicePlayBack(@PathVariable("id") Long characterId) {
        log.info("[角色音频播放] characterId={}", characterId);
        return characterInfoService.voicePlayBack(characterId);
    }

    /**
     * 角色音频播放（流式）
     * @param characterId 角色ID
     * @return SSE流式音频响应
     */
    @GetMapping("/voiceStreamPlay/{id}")
    public SseEmitter voiceStreamPlayBack(@PathVariable("id") Long characterId) {
        log.info("[角色音频流式播放] characterId={}", characterId);
        return characterInfoService.voicePlayBackWithSse(characterId);
    }

    // ====== 私有方法：AI 辅助生成 ======

    private  String generateIntro(String prompt) {
        try {
            String sys = "你是一个擅长写产品卡片文案的助手。根据角色提示词，生成50-80字中文简介，突出能力与适用场景，语气专业友好。只输出正文，不要加标题。";
            GenerationParam param = GenerationParam.builder()
                    .apiKey(aiConfig.getDashscope().getApiKey())
                    .model(aiConfig.getDashscope().getChatModel())
                    .messages(Arrays.asList(
                            Message.builder().role(Role.SYSTEM.getValue()).content(sys).build(),
                            Message.builder().role(Role.USER.getValue()).content(prompt).build()
                    ))
                    .resultFormat(GenerationParam.ResultFormat.MESSAGE)
                    .build();
            Generation gen = new Generation();
            GenerationResult res = gen.call(param);
            return res.getOutput().getChoices().get(0).getMessage().getContent();
        } catch (Exception e) {
            log.error("简介生成失败", e);
            return null;
        }
    }

    /**
     *
     * AI辅助生成角色标签
     * @param prompt
     * @return
     */
    private List<String> generateTags(String prompt) {
        try {
            String sys = "根据角色提示词，返回一个 JSON 数组，包含3-6个不超过4字的中文短标签。只输出JSON数组，不要输出其他内容。";
            GenerationParam param = GenerationParam.builder()
                    .apiKey(aiConfig.getDashscope().getApiKey())
                    .model(aiConfig.getDashscope().getChatModel())
                    .messages(Arrays.asList(
                            Message.builder().role(Role.SYSTEM.getValue()).content(sys).build(),
                            Message.builder().role(Role.USER.getValue()).content(prompt).build()
                    ))
                    .resultFormat(GenerationParam.ResultFormat.MESSAGE)
                    .build();
            Generation gen = new Generation();
            GenerationResult res = gen.call(param);
            String content = res.getOutput().getChoices().get(0).getMessage().getContent();
            List<String> arr = OBJECT_MAPPER.readValue(content, OBJECT_MAPPER.getTypeFactory().constructCollectionType(List.class, String.class));
            List<String> cleaned = new ArrayList<>();
            for (String s : arr) { if (!isBlank(s)) cleaned.add(s.trim()); }
            return cleaned;
        } catch (Exception e) {
            log.error("标签生成失败", e);
            return null;
        }
    }

    /**
     * AI辅助生成角色招呼语
     * @param name
     * @param prompt
     * @return
     */
    private String generateGreeting(String name, String prompt) {
        try {
            String sys = "你是一个擅长创作角色对话的助手。根据角色名称和提示词，生成一句20-40字的中文招呼语，要符合角色性格，语气自然亲切，适合作为对话开场白。只输出招呼语内容，不要加引号或其他格式。";
            String userPrompt = "角色名称：" + name + "\n角色设定：" + prompt;
            GenerationParam param = GenerationParam.builder()
                    .apiKey(aiConfig.getDashscope().getApiKey())
                    .model(aiConfig.getDashscope().getChatModel())
                    .messages(Arrays.asList(
                            Message.builder().role(Role.SYSTEM.getValue()).content(sys).build(),
                            Message.builder().role(Role.USER.getValue()).content(userPrompt).build()
                    ))
                    .resultFormat(GenerationParam.ResultFormat.MESSAGE)
                    .build();
            Generation gen = new Generation();
            GenerationResult res = gen.call(param);
            return res.getOutput().getChoices().get(0).getMessage().getContent();
        } catch (Exception e) {
            log.error("招呼语生成失败", e);
            return null;
        }
    }

    /**
     * 转换角色信息为收藏列表响应格式
     */
    private FavoriteCharacterInfo convertToFavoriteInfo(CharacterInfo character) {
        FavoriteCharacterInfo info = new FavoriteCharacterInfo();
        info.setId(character.getId());
        info.setName(character.getName());
        info.setIntro(character.getIntro());
        info.setImage(character.getImage());
        info.setViewCount(character.getViewCount());
        info.setCreateTime(character.getCreateTime());
        info.setTags(character.getTags());
        info.setGreeting(character.getGreeting());
        return info;
    }

    private boolean isBlank(String s) { return s == null || s.trim().isEmpty(); }
    private String nullToEmpty(String s) { return s == null ? "" : s; }

    /**
     * 创建角色请求体（保存用户已确定的信息）
     * - 字段：包含用户分步创建时已确定的所有字段
     * - 说明：直接保存，不再重新生成任何内容
     */
    @lombok.Data
    public static class CreateReq {
        public String name;        // 必填：角色名称
        public String prompt;      // 必填：角色提示词
        public String intro;       // 可选：角色简介
        public String image;       // 可选：头像URL
        public String voice;       // 可选：音色ID
        public String voiceUrl;    // 可选：自定义音色音频URL
        public String category;    // 可选：角色分类
        public List<String> tags;  // 可选：角色标签
        public String greeting;    // 可选：招呼语
    }

    /**
     * 收藏角色信息响应体
     * - 字段：id、name、intro、image、view_count、create_time、tags、greeting
     */
    @lombok.Data
    public static class FavoriteCharacterInfo {
        public Long id;              // 角色ID
        public String name;          // 角色名称
        public String intro;         // 角色简介
        public String image;         // 头像URL
        public Integer viewCount;    // 访问量
        public Date createTime;      // 创建时间
        public List<String> tags;   // 角色标签
        public String greeting;     // 招呼语
    }
}
